#pragma once

namespace base
{

class CLock
{
public:
	CLock(VOID);
	~CLock(VOID);

	VOID Acquire();
	VOID Release();
	BOOL Try();

private:
	CRITICAL_SECTION m_cs;

private:
	CLock(const CLock& right);
	CLock & operator =(const CLock & right);
};

class CAutoLock
{
public:
	explicit CAutoLock(CLock & Lock)
		: m_Lock(Lock)
	{
		m_Lock.Acquire();
	}

	~ CAutoLock()
	{
		m_Lock.Release();
	}

private:
	CLock & m_Lock;

private:
	CAutoLock(const CAutoLock& right);
	CAutoLock & operator == (const CAutoLock & right);
};

class CReadWriteLock
{
public:
	class CReadWriteLockGuard
	{
	public:
		enum READ_WRITE_LOCK_TYPE
		{
			RWLT_READ_LOCK = 0,
			RWLT_WRITE_LOCK = 1,
		};

	public:
		CReadWriteLockGuard(CReadWriteLock& Locker, READ_WRITE_LOCK_TYPE eLockType)
			: m_Locker(Locker)
		{
			if (RWLT_READ_LOCK == eLockType)
			{
				m_Locker.ReadAcquire();
			}
			else
			{
				m_Locker.WriteAcquire();
			}
		}

		~CReadWriteLockGuard()
		{
			m_Locker.Release();
		}

	private:
		CReadWriteLock& m_Locker;
	};

private:
	INT		m_nActive;		// 0 : no use, -1 : writing, >0 : number of reader
	CRITICAL_SECTION	m_cs;		

	INT		m_nWaitingReaders;
	INT		m_nWaitingWriters;
	HANDLE	m_hsemReaders;
	HANDLE	m_hsemWriters;

public:
	CReadWriteLock();
	~CReadWriteLock();

	VOID ReadAcquire();
	VOID WriteAcquire();

	VOID Release();
};
}